#include "m_cmd_decode.h"
#include "m_log.h"
#include "m_utils.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 *  保留不完整包
 */
static void m_cache(decode_cache *cache, char *data, unsigned int size)
{
    #ifdef M_LOG_DEBUG
    unsigned char hex[size * 2];
    m_to_hex(data, size, hex);
    m_log_d(M_CMD_DECODE_H, "append->: %s\n", hex);
    #endif

    for (int i = 0; i < size; i++) {
        cache->buf[cache->size + i] = *(data + i) & 0xFF;
    }
    cache->size += size;
    free(data);
}

static void m_toEnd(decode_data *data)
{
    data->index = 0;
}
/**
 * 查找并定位到报文中下一条指令开头处
 */
static void m_toNext(decode_cache *cache, decode_data *data, unsigned int skip)
{
    cache->size = 0;
    // 查找下一个包头
    for (unsigned int i = data->index + skip; i < data->size; i++) {
        if ((data->buf[i] & 0xFF) == PK_HEAD && ( ( i + 1 ) == data->size || (data->buf[i + 1] & 0xFF) == PK_HEAD ) ) {
            data->index = i;
            return;
        }
    }
    m_toEnd(data);
}

int m_decode(decode_cache *cache, decode_data *data, decode_result *result)
{
    if (data == NULL || data->size == 0) {
        return 1;
    }

    unsigned char *rData;// remainData => cache->buf + data
    unsigned int rSize = data->size - data->index;// remainSize

    if (cache->size > 0 && ( cache->buf[0] & 0xFF ) == PK_HEAD && (cache->size == 1 || ( cache->buf[1] & 0xFF ) == PK_HEAD ) ) {

        #ifdef M_LOG_DEBUG
        unsigned char hex[cache->size * 2];
        m_to_hex(cache->buf, cache->size, hex);
        m_log_d(M_CMD_DECODE_H, "cache->buf->: %s\n", hex);
        #endif

        rSize += cache->size;
        rData = (unsigned char *) malloc(rSize * sizeof(char) );

        for (int i = 0; i < cache->size; i++) {
            rData[i] = cache->buf[i];
        }
        for (int i = 0; i < rSize - cache->size; i++) {
            rData[cache->size + i] = data->buf[data->index + i];
        }

    } else {
        rData = (unsigned char *)malloc( rSize * sizeof(char) );
        for (int i = 0; i < rSize; i++) {
            rData[i] = data->buf[data->index + i];
        }
    }

    /*//log
    printf("rData->");
    for (int i = 0; i < rSize; i++) {
        printf("%02x", rData[i] & 0xFF);
    }
    printf("\n");
    */

    // 包头大小
    if (rSize < 2) {
        m_log_d(M_CMD_DECODE_H, "cmd->invald actual length: %d\n", rSize);
        if ((rData[0] & 0xFF) == PK_HEAD) {
            m_cache(cache, rData, rSize);
        }
        free(rData);
        m_toEnd(data);
        return 1;
    }

    // 包头
    if ((rData[0] & 0xFF) != PK_HEAD || (rData[1] & 0xFF) != PK_HEAD ) {
        #ifdef M_LOG_DEBUG
        m_log_d(M_CMD_DECODE_H, "cmd->invald head\n");
        unsigned char hex[cache->size * 2];
        m_to_hex(cache->buf, cache->size, hex);
        m_log_d(M_CMD_DECODE_H, "cache->buf->: %s\n", hex);
        #endif
        // 查找下一个包头
        free(rData);
        m_toNext(cache, data, cache->size > 0 ? 0: 2);
        if ((rData[0] & 0xFF) == 0x31) {
            return 1;
        }
        return 2;
    }

    // 标准包至少大小
    if (rSize < PK_MIN) {
        m_log_d(M_CMD_DECODE_H, "cmd->invald actual min length: %d, min: %d\n", rSize, PK_MIN);
        m_cache(cache, rData, rSize);
        m_toEnd(data);
        return 1;
    }

    // 包内信息表明的当前包长度
    unsigned int pSize = ((rData[2] & 0xFF) << 8) | (rData[3] & 0xFF); // package size

    // 包内信息表明的长度信息与实际数据长度比较
    if (rSize < pSize) {
        m_log_d(M_CMD_DECODE_H, "cmd->invald content length: pk=%d, actual=%d\n", pSize, rSize);
        if (pSize > PK_MAX) {
            free(rData);
            m_toNext(cache, data, rSize - cache->size);
        } else {
            m_cache(cache, rData, rSize);
            m_toEnd(data);
        }
        return 1;
    }

    // 包尾
    if ((rData[pSize - 1] & 0xFF) != PK_TAIL || (rData[pSize - 2] & 0xFF) != PK_TAIL ) {
        m_log_d(M_CMD_DECODE_H, "cmd->invald tail\n");
        m_cache(cache, rData, rSize);
        m_toEnd(data);
        return 1;
    }

    // 校验值
    int crc = 0;
    //printf("check->");
    for (int i = 2; i < pSize - 3; i++) {
        crc ^= rData[i] & 0xFF;
        //printf("%02x", rData[i] & 0xFF);
    }
    //printf("\n");

    if ((crc & 0xFF) != (rData[pSize - 3] & 0xFF)) {
        m_log_d(M_CMD_DECODE_H, "cmd->invald crc: pk=%d, actual=%d\n", rData[pSize - 3] & 0xFF, crc & 0xFF);
        free(rData);
        m_toNext(cache, data, pSize - cache->size);
        return 1;
    }

    #ifdef M_LOG_DEBUG
    unsigned char hex[pSize * 2];
    m_to_hex(rData, pSize, hex);
    m_log_d(M_CMD_DECODE_H, "cmd->: %s\n", hex);
    #endif

    result->ackType = (unsigned int)((rData[4] & 0x80) >> 7);
    result->bizType = (unsigned int)(rData[4] & 0x7F);
    result->serialNo = (unsigned int)((rData[5] & 0xFF) << 8) | (rData[6] & 0xFF);
    result->size = pSize - PK_MIN;
    for (int i = 0; i < result->size; i++) {
        *(result->buf + i) = *(rData + i + 7) & 0xFF;// 包中第7个字节开始才是业务数据
    }

    free(rData);
    m_toNext(cache, data, pSize - cache->size);
    return 0;
}
